import { _decorator, Button, Camera, Color, Component, EventTouch, geometry, Input, input, instantiate, Label, Layout, Mat4, Node, Prefab, random, Size, size, tween, UIOpacity, UITransform, Vec2, Vec3, Vec4 } from 'cc';
import { Singleton } from './comm/Singleton';
import { Cell } from './Cell';
import { CellData, GameData, LevelData } from './GameData';
import { XUtils } from './comm/XUtils';
import { UIManager } from './ui/UIManager';
import { CommTweens } from './comm/CommTweens';
const { ccclass, property } = _decorator;

@ccclass('GameCtrl')
export class GameCtrl extends Singleton<GameCtrl> {
    

    isWin: boolean = false;
    isLeft: boolean = true;
    currentLevel: LevelData;
    cellList: Cell[] = [];
    cellTextList: Label[] = [];

    @property(Node)
    cellParent: Node;
    @property(Node)
    cellTextParent: Node;
    @property(Node)
    gameArea: Node;
    @property(UITransform)
    tapArea: UITransform;
    @property(Prefab)
    cellPrafab: Prefab;
    @property(Prefab)
    cellTextPrafab: Prefab;
    @property(Camera)
    gameCamera: Camera;
    @property(Node)
    UIGame: Node;

    @property(Node)
    mask: Node;
    @property(Node)
    tapMask: Node;
    @property(Node)
    tapText: Node;

    @property(Node)
    gameNd: Node;


    public startGame(level: number){
        //this.mask.active = true;
        this.onEventListeners();
        this.currentLevel = GameData.Instance.createLevel(level);
        this.UIGame.active = true;
        this.firstClick = true;
        this.isWin = false;
        this.initLevel();
    }

    public continueGame(level: number){
        this.onEventListeners();

        this.mask.active = false;
        this.tapMask.active = false;

        this.currentLevel = GameData.Instance.getLevel(level);
        this.UIGame.active = true;
        this.firstClick = false;
        this.isWin = false;
        this.loadLevel();
    }

    public async initLevel(){
        this.tapArea.contentSize = this.calTapAreaSize();
        this.gameArea.getComponent(UITransform).contentSize = this.calTapAreaSize();
        this.cellTextParent.getComponent(UITransform).contentSize = this.calTapAreaSize();
        this.tapMask.getChildByName('TapArea').getComponent(UITransform).contentSize = this.calTapAreaSize();
        //this.gameCamera.orthoHeight = this.calOrthoHitht();
        this.gameNd.scale = this.calScale();

        UIManager.Instance.getUI('UILayer').setMineText();

        await this.createCell();

        this.gameArea.active = false;

        console.log(this.calTapAreaSize());

        tween(this.tapMask.getComponent(UITransform)).to(1.5,{
            contentSize: this.calTapAreaSize()
       }).call(()=>{
            this.mask.active = false;
            console.log(this.tapText);
            this.tapText.active = true;
            this.gameArea.active = true;

            //console.log(this.gameArea.getComponent(UITransform).contentSize , this.gameCamera.orthoHeight , this.tapMask.getComponent(UITransform).contentSize, this.tapArea.contentSize)
       }).start();
    }

    public async loadLevel(){
        this.tapArea.contentSize = this.calTapAreaSize();
        this.gameArea.getComponent(UITransform).contentSize = this.calTapAreaSize();
        this.cellTextParent.getComponent(UITransform).contentSize = this.calTapAreaSize();
        //this.gameCamera.orthoHeight = this.calOrthoHitht();
        this.gameNd.scale = this.calScale();

        UIManager.Instance.getUI('UILayer').setMineText();

        await this.createCell();

        for(let i = 0; i < this.cellList.length; i++){
            this.cellList[i].index = this.currentLevel.cellList[i].index;
            this.cellList[i].IsFilp = this.currentLevel.cellList[i].IsFilp;
            this.cellList[i].IsHide = this.currentLevel.cellList[i].IsHide;
            this.cellList[i].IsMine = this.currentLevel.cellList[i].IsMine;
            this.cellList[i].MineNum = this.currentLevel.cellList[i].MineNum;

            if(this.cellList[i].IsFilp && this.cellList[i].MineNum > 0){
                this.cellTextList[i].getComponent(Label).string = this.cellList[i].MineNum.toString();
                this.cellTextList[i].getComponent(UIOpacity).opacity = 255;
            }
        }

        this.restore();

    }

    public restore(){
        tween(this.gameArea).to(1,{
            position: this.currentLevel.position
        },{
             easing: 'sineInOut'
        }).start();

        tween(this.cellTextParent).to(1,{
            position: this.currentLevel.position
        },{
             easing: 'sineInOut'
        }).start();

        // tween(this.gameCamera).to(1,{
        //     orthoHeight: this.currentLevel.orthoHeight
        // },{
        //      easing: 'sineInOut'
        // }).start();

        tween(this.gameNd).to(1,{
            scale: Vec3.ONE
        },{
             easing: 'sineInOut'
        }).start();

        // tween(this.gameArea).to(1,{
        //     scale: Vec3.ONE
        // },{
        //      easing: 'sineInOut'
        // }).start();
        // tween(this.cellTextParent).to(1,{
        //     scale: Vec3.ONE
        // },{
        //      easing: 'sineInOut'
        // }).start();
    }



    public async createCell(){
        return new Promise<void>((resolve) => {
            for(let i = 0; i < this.getLength(); i++){
                const cell = instantiate(this.cellPrafab);
                cell.setParent(this.cellParent);
                const celljs = cell.getComponent(Cell);
                celljs.index = i;
                celljs.IsFilp = false;
                celljs.IsHide = false;
                celljs.IsMine = false;
                celljs.MineNum = 0;
                this.cellList.push(celljs);

                const cellText = instantiate(this.cellTextPrafab);
                cellText.setParent(this.cellTextParent);
                cellText.getComponent(UIOpacity).opacity = 0;
                this.cellTextList.push(cellText.getComponent(Label));
            }
            
            setTimeout(() => {
                resolve();
            }, 0);
        });
    }


    hori: number;
    ver: number;
    public createMine(index: number) {
        let mines: number[] = [];
        const total = this.getLength();
        const mineNum = this.currentLevel.mineNum;

        // 生成索引
        for (let i = 0; i < total; i++) {
            mines.push(i);
        }


        let i = mines.indexOf(index);
        mines.splice(i,1);
        let _ver = Math.floor(index / this.currentLevel.col);
        let _hori = index % this.currentLevel.col;

        for (let d = 0; d < 8; d++) {
            let newRow = _ver + this.dir[d][0];
            let newCol = _hori + this.dir[d][1];

            if (
                newRow >= 0 && newRow < this.currentLevel.row &&
                newCol >= 0 && newCol < this.currentLevel.col
            ) {
                let neighborIndex = XUtils.TwoDimensionalToOne(newRow, newCol, this.currentLevel.col);
                let i = mines.indexOf(neighborIndex);
                if(i != -1)
                    mines.splice(i,1);
            }
        }

        // 洗牌
        for (let i = 0; i < mines.length; i++) {
            let random = XUtils.randomRangeInt(i, mines.length);
            let temp = mines[i];
            mines[i] = mines[random];
            mines[random] = temp;
        }

        // 只取前mineNum个
        for (let i = 0; i < mineNum; i++) {
            this.cellList[mines[i]].IsMine = true;
            this.currentLevel.mineList.push(mines[i]);

            this.hori = mines[i] % this.currentLevel.col;
            this.ver = Math.floor(mines[i] / this.currentLevel.col);

            for (let d = 0; d < 8; d++) {
                let newRow = this.ver + this.dir[d][0];
                let newCol = this.hori + this.dir[d][1];

                if (
                    newRow >= 0 && newRow < this.currentLevel.row &&
                    newCol >= 0 && newCol < this.currentLevel.col
                ) {
                    let neighborIndex = XUtils.TwoDimensionalToOne(newRow, newCol, this.currentLevel.col);
                    this.cellList[neighborIndex].MineNum++;
                    this.cellTextList[neighborIndex].string = this.cellList[neighborIndex].MineNum.toString();
                }
            }
        }
    }







    dir:number[][] = [
        [ 0,  1 ],  // 上
        [ 0, -1 ],  // 下
        [-1,  0 ],  // 左
        [ 1,  0 ],  // 右
        [-1,  1 ],  // 左上
        [-1, -1 ],  // 左下
        [ 1,  1 ],  // 右上
        [ 1, -1 ]   // 右下
    ];
    public async handleLeftClick(cell: Cell){
        if(cell.IsMine && !cell.IsFilp){
            cell.showBow();
            this.handleLose();
            return;
        }

        if(!cell.IsMine && !cell.IsFilp && !cell.IsHide){
            let visited = new Set<number>();
            visited.add(cell.index);
            let preFrameHandleCellNum = 8;
            let handleCellTime = 0.05;

            let bfs: number[] = [];
            bfs.push(cell.index);

            while(bfs.length > 0){
                const actualFrameCount = this.calculateActualFrameCount(bfs,visited);

                let lastFrameHanleCellNum = 0;

                while(bfs.length > 0 && lastFrameHanleCellNum < actualFrameCount){
                    let index = bfs.shift();
                    let _hori = index % this.currentLevel.col;
                    let _ver = Math.floor(index / this.currentLevel.col);


                    this.cellList[index].IsFilp = true;
                    if(this.cellList[index].MineNum != 0){
                        //this.cellList[index].lbMine.node.active = true;
                        this.cellTextList[index].getComponent(UIOpacity).opacity = 255;
                    }
                        

                    if(this.cellList[index].MineNum == 0){
                        for(let d = 0; d < 8; d++){
                            let newRow = _ver + this.dir[d][0];
                            let newCol = _hori + this.dir[d][1];
                            if(newRow >= 0 && newRow < this.currentLevel.row &&
                                newCol >= 0 && newCol < this.currentLevel.col
                            ){
                                let _index = XUtils.TwoDimensionalToOne(newRow,newCol,this.currentLevel.col);

                                if (
                                    !this.cellList[_index].IsMine &&
                                    !this.cellList[_index].IsHide &&
                                    !this.cellList[_index].IsFilp 
                                ) {
                                    if(!visited.has(_index)){
                                        visited.add(_index);
                                        bfs.push(_index);
                                    }
                                }
                            }         
                        }
                    }
                    lastFrameHanleCellNum++;
                }
                preFrameHandleCellNum *= 2;

                await this.waitForSeconds(handleCellTime);
            }
            
        }
    }

    private calculateActualAdjacentCount(index: number, visited: Set<number>): number {
        let count = 0;
        const _hori = index % this.currentLevel.col;
        const _ver = Math.floor(index / this.currentLevel.col);
        
        for (let d = 0; d < 8; d++) {
            const newRow = _ver + this.dir[d][0];
            const newCol = _hori + this.dir[d][1];
            
            if (newRow >= 0 && newRow < this.currentLevel.row &&
                newCol >= 0 && newCol < this.currentLevel.col) {
                const _index = XUtils.TwoDimensionalToOne(newRow, newCol, this.currentLevel.col);
                
                if (!this.cellList[_index].IsMine &&
                    !this.cellList[_index].IsHide &&
                    !this.cellList[_index].IsFilp &&
                    !visited.has(_index)) {
                    count++;
                }
            }
        }
        return count;
    }

    private calculateActualFrameCount(currentBfs: number[], visited: Set<number>): number {
        let totalAdjacent = 0;
        
        // 计算当前队列中所有格子的实际可添加数
        for (const index of currentBfs) {
            totalAdjacent += this.calculateActualAdjacentCount(index, visited);
        }
        
        // 根据实际可添加数动态调整处理数量
        const baseCount = 8;
        const actualCount = Math.min(baseCount, Math.max(1, Math.floor(totalAdjacent / 2)));
        
        return actualCount;
    }

    waitForSeconds(seconds: number): Promise<void> {
        return new Promise(resolve => this.scheduleOnce(resolve, seconds));
    }


    public handleRightClick(cell: Cell){
        if(cell.IsHide){
            cell.IsHide = false;
            this.currentLevel.mineNum++;
            UIManager.Instance.getUI('UILayer').setMineText();
            return;
        }
        if(!cell.IsFilp){
            cell.IsHide = true;
            this.currentLevel.mineNum--;
            UIManager.Instance.getUI('UILayer').setMineText();
            if(this.currentLevel.mineNum == 0 && this.checkWin()){
                this.handleWin();
            }
        }
        
    }


    public checkWin(){
        let isWin = true;
        this.currentLevel.mineList.forEach(e => {
            isWin = isWin && this.cellList[e].IsHide;
        })

        return isWin;
    }

    public async handleWin(){
        this.resetCell();

        this.isWin = true;
        this.mask.active = true;
        
        // tween(this.gameCamera).to(1,{
        //     orthoHeight: this.calOrthoHitht()
        // },{
        //     easing: 'sineInOut'
        // }).start();
        // tween(this.gameArea).to(1,{
        //     scale: Vec3.ONE
        // },{
        //      easing: 'sineInOut'
        // }).start();
        // tween(this.cellTextParent).to(1,{
        //     scale: Vec3.ONE
        // },{
        //      easing: 'sineInOut'
        // }).start();

        tween(this.gameNd).to(1,{
            scale: this.calScale()
        },{
            easing: 'sineInOut'
        }).start();

        tween(this.gameArea).to(1,{
            position: Vec3.ZERO
        },{
            easing: 'sineInOut'
        }).start();
        tween(this.cellTextParent).to(1,{
            position: Vec3.ZERO
        },{
            easing: 'sineInOut'
        }).start();

        for(let i = 0; i < this.currentLevel.recardStep.length; i++){
            if(this.currentLevel.stepLeftOrRight[i]){
                this.handleLeftClick(this.cellList[i]);
            }else{
                this.handleRightClick(this.cellList[i]);
            }

            await this.waitForSeconds(0.05);
        }
    }

    public async handleLose(){
        this.mask.active = true;
        this.isWin = true;

        // tween(this.gameCamera).to(1,{
        //     orthoHeight: this.calOrthoHitht()
        // },{
        //     easing: 'sineInOut'
        // }).start();
        // tween(this.cellTextParent).to(1,{
        //     scale: Vec3.ONE
        // },{
        //     easing: 'sineInOut'
        // }).start();
        // tween(this.gameArea).to(1,{
        //     scale: Vec3.ONE
        // },{
        //     easing: 'sineInOut'
        // }).start();

        tween(this.gameNd).to(1,{
            scale: this.calScale()
        },{
            easing: 'sineInOut'
        }).start();

        tween(this.gameArea).to(1,{
            position: Vec3.ZERO
        },{
            easing: 'sineInOut'
        }).start();
        tween(this.cellTextParent).to(1,{
            position: Vec3.ZERO
        },{
            easing: 'sineInOut'
        }).start();

        for(let i = 0; i < this.currentLevel.mineList.length; i++){

            if(this.cellList.length == 0) return;

            this.cellList[this.currentLevel.mineList[i]].showMine();
               
            await this.waitForSeconds(0.05);
        }
    }




    private getLength(){
        return this.currentLevel.row * this.currentLevel.col;
    }

    private calTapAreaSize(){
        const layout = this.gameArea.getComponent(Layout);
        let cellSize = 60;
        if (this.cellParent.children.length > 0) {
            cellSize = this.cellParent.children[0].getComponent(UITransform).contentSize.x;
        }
        let y = layout.paddingBottom + layout.paddingTop + (this.currentLevel.row * cellSize) + (this.currentLevel.row - 1) * layout.spacingY;
        let x = layout.paddingLeft + layout.paddingRight + (this.currentLevel.col * cellSize) + (this.currentLevel.col - 1) * layout.spacingX;
        return new Size(x, y);
    }

    private calScale(){
        if(this.currentLevel.level == 1){
            return Vec3.ONE;
        }else{
            const size = new Vec2(436,622);
            const _size = this.calTapAreaSize();
            return new Vec3(size.x/_size.x, size.y/_size.y,1);
        }
    }

    private calOrthoHitht(){
        if(this.currentLevel.level == 1){
            return 667;
        }else{
            return 667 * this.gameArea.getComponent(UITransform).contentSize.y / 622;
        }
    }

    firstClick: boolean = true;
    public handleFirstClick(index: number){
        if(this.firstClick){
            this.tapMask.active = false;
            this.tapText.active = false;
            //this.onEventListeners();
            this.createMine(index)
            this.firstClick = false;

            // tween(this.gameCamera).to(1,{
            //     orthoHeight: 667
            // },{
            //     easing: 'sineInOut'
            // }).start();
            tween(this.gameNd).to(1,{
                scale: Vec3.ONE
            },{
                easing: 'sineInOut'
            }).start();
            // tween(this.cellTextParent).to(1,{
            //     scale: Vec3.ONE
            // },{
            //     easing: 'sineInOut'
            // }).start();
        }
    }

    public saveGame(){

        if(!this.isWin && !this.firstClick){
            for(let i = 0; i < this.cellList.length; i++){
                this.currentLevel.cellList.push(
                    new CellData(
                        this.cellList[i].index,
                        this.cellList[i].IsFilp,
                        this.cellList[i].IsHide,
                        this.cellList[i].IsMine,
                        this.cellList[i].MineNum,
                    )
                )
            }

            this.currentLevel.position = this.gameArea.position.clone();
            this.currentLevel.scale = this.gameNd.scale;

            GameData.Instance.saveLevel(this.currentLevel.level,this.currentLevel);
        }

        this.resetTapMask();

        this.gameNd.scale = Vec3.ONE;

        this.cellParent.destroyAllChildren();
        this.cellTextParent.destroyAllChildren();
        this.gameArea.position = Vec3.ZERO;
        this.cellTextParent.position = Vec3.ZERO;
        this.firstClick = false;

        this.cellList = [];
        this.cellTextList = [];

        this.offEventListeners();

        
    }


    public resetTapMask(){
        this.tapMask.active = true;
        this.tapMask.getComponent(UITransform).contentSize = new Size(100,100);
        this.tapText.active = false;
    }

    public resetCell(){
        this.cellList.forEach(e => {
            e.resetCell();
        })
    }





    public _dragging = false;
    public _scaling = false;
    public _isCellON = false;
    public _isCellScaleOn = false;

    public _isEdgeDamping = false;

    public _dragOffset = new Vec3();
    public _lastTouchPos: Vec3 = new Vec3(); 

    public _pointer1 = new Vec2();
    public _pointer2 = new Vec2();
    public _initDistance = 0;
    public _initOrthoHeight = 0;
    public initOrthoHeight = 667;

    public _initScale = 1;

    public currPointer1 = new Vec2() ;
    public currPointer2 = new Vec2() ;



    onEventListeners() {
        input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
        input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    offEventListeners() {
        input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
        input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
        input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
        input.off(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    private onTouchStart(event: EventTouch) {
        tween(this.gameArea).stop();
        tween(this.cellTextParent).stop();
        const touches = event.getAllTouches();
        if(touches.length == 2 && !this._scaling){
            this._dragging = false;
            this._scaling = true;
            this._pointer1 = touches[0].getUILocation();
            this._pointer2 = touches[1].getUILocation();
            this._initDistance = this._pointer1.subtract(this._pointer2).length();
            this._initScale = this.gameNd.scale.x;
        }else if(touches.length == 1){
            this._scaling = false;
            this._dragging = true;
            const parent = this.gameArea.parent!;
            this._pointer1 = event.getUILocation();
            const localPos = parent.getComponent(UITransform)!.convertToNodeSpaceAR(new Vec3(this._pointer1.x, this._pointer1.y, 0));
            this._dragOffset = this.gameArea.position.clone().subtract(localPos);
        }
        this._lastMoveTime = 0;
        this._velocity.set(0, 0, 0);
    }

    private onTouchMove(event: EventTouch) {
        const touches = event.getTouches();
        if(this._scaling && touches.length == 2){
            this._dragging = false;
            const currPointer1 = touches[0].getUILocation();
            const currPointer2 = touches[1].getUILocation();
            const currDistance = currPointer1.subtract(currPointer2).length();
            const scale = currDistance / this._initDistance;
            let newScale = scale * this._initScale;
            newScale = Math.max(this.calScale().x, Math.min(2.0, newScale));
            //this.gameNd.setScale(newScale, newScale, 1);
            tween(this.gameNd).stop();
            tween(this.gameNd)
                .to(0.08, { scale: new Vec3(newScale, newScale, 1) }, { easing: 'quadOut' })
                .start();
        }
        if (this._dragging && !this.firstClick){
            this._scaling = false;
            const parent = this.gameArea.parent!;
            const currentPos2 = event.getUILocation();
            const localPos = parent.getComponent(UITransform)!.convertToNodeSpaceAR(new Vec3(currentPos2.x, currentPos2.y, 0));
            let newPos = localPos.add(this._dragOffset);


            this.gameArea.setPosition(newPos);
            this.cellTextParent.setPosition(this.gameArea.position);

            // if(Vec3.distance(this.gameArea.position,Vec3.ZERO) > this.currentLevel.safeDistance){
            //     this._dragging = false;
            //     const from = this.gameArea.position.clone();
            //     const to = Vec3.ZERO;
            //     const dir = from.subtract(to).normalize();
            //     const target = from.subtract(dir.multiplyScalar(this.currentLevel.safeDistance));
            //     target.z = from.z; 
            //     tween(this.gameArea).to(1,{
            //         position: target
            //     },{
            //         easing: 'cubicOut'
            //     }).start();
            //     tween(this.cellTextParent).to(1,{
            //         position: target
            //     },{
            //         easing: 'cubicOut'
            //     }).start();
            // }


            const now = performance.now();
            const pos = this.gameArea.position.clone();
            if (this._lastMoveTime > 0) {
                const dt = (now - this._lastMoveTime) / 1000;
                if (dt > 0) {
                    this._velocity = pos.subtract(this._lastMovePos).multiplyScalar(1 / dt);
                }
            }
            this._lastMoveTime = now;
            this._lastMovePos = pos;
        }
    }

    private onTouchEnd(event: EventTouch) {
        this._pointer2 = event.getUILocation();
        if(Vec2.distance(this._pointer1,this._pointer2) <= 1 && !this._scaling){
            const uiTransform = this.gameArea.getComponent(UITransform);
            const screenPos = this._pointer1;

            
            const localPos = uiTransform.convertToNodeSpaceAR(new Vec3(screenPos.x,screenPos.y,0));



            const halfWidth = uiTransform.width  / 2;
            const halfHeight = uiTransform.height  / 2;

            if(  localPos.x >= -halfWidth && localPos.x <= halfWidth &&
    localPos.y >= -halfHeight && localPos.y <= halfHeight){
                

                //点击
                const cell = this.cellList[0].getComponent(UITransform).contentSize;
                //const cellSize = new Size(cell.x * this.gameNd.scale.x , cell.y * this.gameNd.scale.y);
                const spacing = this.gameArea.getComponent(Layout).spacingX;
                const stepX = cell.x + spacing;
                const stepY = cell.y + spacing;

                //this.gameArea.setScale(this.gameArea.scale.x+0.1,this.gameArea.scale.y+0.1),this.gameArea.scale.z+0.1;

                const localX = localPos.x + halfWidth;
                const localY = halfHeight - localPos.y;

                const _col = Math.floor(localX / stepX);
                const _row = Math.floor(localY / stepY);

                console.log(`点击位置: (${localX}, ${localY}), 计算行列: (${_row}, ${_col})`);

                if (_row >= 0 && _row < this.currentLevel.row && _col >= 0 && _col < this.currentLevel.col) {
                    const index = XUtils.TwoDimensionalToOne(_row, _col, this.currentLevel.col);
                    this.handleFirstClick(index);
                    this.cellList[index].Click();
                }
            }
        }

        this._dragging = false;
        this._scaling = false;
        this._lastMoveTime = 0;
    }


    protected update(dt: number): void {
        if(this._isCellON){
            // 只在长按格子拖拽模式下生效
            const parent = this.gameArea.parent!;
            const localPos = parent.getComponent(UITransform)!.convertToNodeSpaceAR(this._lastTouchPos);
            let newPos = localPos.add(this._dragOffset);
            this.gameArea.setPosition(newPos);
            this.cellTextParent.setPosition(this.gameArea.position);
        }
        if(this._isCellScaleOn && this.currPointer1 && this.currPointer2){
            const currDistance = this.currPointer1.subtract(this.currPointer2).length();
            const scale = currDistance / this._initDistance;
            let newOrthoHeight = this._initOrthoHeight / scale;
            newOrthoHeight = Math.max(300, Math.min(1200, newOrthoHeight));
            this.gameCamera.orthoHeight = newOrthoHeight;
        }
    }


    private _lastMoveTime = 0;
    private _lastMovePos = new Vec3();
    private _velocity = new Vec3();
    private _inertiaId: number | null = null;

    private startInertiaScroll() {
        const friction = 0.95; // 摩擦系数，越小越快停
        const minSpeed = 10;   // 最小速度，低于此值就停

        if (this._inertiaId) {
            cancelAnimationFrame(this._inertiaId);
        }

        const step = () => {
            // 速度衰减
            this._velocity.multiplyScalar(friction);

            // 位置更新
            let pos = this.gameArea.position.clone().add(this._velocity.clone().multiplyScalar(1/60));
            // 边界检测
            let clamped = this.clampGameAreaPosition(pos);
            if (!pos.equals(clamped)) {
                // 到边界，回弹
                this.gameArea.setPosition(clamped);
                this._velocity.set(0, 0, 0);
                return;
            } else {
                this.gameArea.setPosition(pos);
            }

            // 速度很小就停
            if (this._velocity.length() > minSpeed) {
                this._inertiaId = requestAnimationFrame(step);
            } else {
                this._velocity.set(0, 0, 0);
            }

            this.cellTextParent.setPosition(this.gameArea.position);
        };

        this._inertiaId = requestAnimationFrame(step);
    }

    private applyDamping(pos: Vec3): { pos: Vec3, isEdgeDamping: boolean } {

        const areaSize = this.gameArea.getComponent(UITransform).contentSize;
        const orthoHeight = this.gameCamera.orthoHeight;
        const canvasWidth = this.UIGame.getComponent(UITransform).contentSize.x;
        const canvasHeight = this.UIGame.getComponent(UITransform).contentSize.y;
        const aspect = canvasWidth / canvasHeight;
        const visibleHeight = orthoHeight * 2;
        const visibleWidth = visibleHeight * aspect;

        const minX = (areaSize.x - visibleWidth) / -2;
        const maxX = (visibleWidth - areaSize.x) / 2;
        const minY = (areaSize.y - visibleHeight) / -2;
        const maxY = (visibleHeight- areaSize.y) / 2;

        // 阻尼系数
        const damping = 0.3;
        let isEdgeDamping = false;

        // X 方向阻尼
        if (pos.x < minX) {
            pos.x = minX + (pos.x - minX) * damping;
            isEdgeDamping = true;
        }
        if (pos.x > maxX) {
            pos.x = maxX + (pos.x - maxX) * damping;
            isEdgeDamping = true;
        }
        // Y 方向阻尼
        if (pos.y < minY) {
            pos.y = minY + (pos.y - minY) * damping;
            isEdgeDamping = true;
        }
        if (pos.y > maxY) {
            pos.y = maxY + (pos.y - maxY) * damping;
            isEdgeDamping = true;
        }

        return { pos, isEdgeDamping };
    }

    private clampGameAreaPosition(pos: Vec3): Vec3 {
        // 获取内容区和当前相机可视区域的尺寸
        const areaSize = this.gameArea.getComponent(UITransform).contentSize;
        const orthoHeight = this.gameCamera.orthoHeight;
        const canvasNode = this.UIGame; 
        const canvasWidth = canvasNode.getComponent(UITransform).contentSize.x;
        const canvasHeight = canvasNode.getComponent(UITransform).contentSize.y;
        const aspect = canvasWidth / canvasHeight;
        const visibleHeight = orthoHeight * 2;
        const visibleWidth = visibleHeight * aspect;

        // 允许的最大偏移
        const minX = (areaSize.x - visibleWidth) / -2;
        const maxX = (visibleWidth - areaSize.x) / 2;
        const minY = (areaSize.y - visibleHeight) / -2;
        const maxY = (visibleHeight - areaSize.y) / 2;

        // 限制位置
        pos.x = Math.max(minX, Math.min(maxX, pos.x));
        pos.y = Math.max(minY, Math.min(maxY, pos.y));
        return pos;
    }
}


